home
lars.st0ne.at
Linux And Related Stuff
[BLOG] |ARCHIVE| |TAG MAP| |OTHER STUFF| |ME|
  • JAX-WS Spring calculator SOAP webservice returning a complex type


    #java #jax-ws #jaxb #jetty #jython #maven #python #soap #suds

    I know there are many webservice howto's out there. My motivation to write an other one was, that all the examples i've found just returning simple types like int or String.

    This tutorial was inspired by this article on www.mkyong.com.

    The Goal:

    A webservice, accepting a mathematical expression as input string and returning a complex type, containing the result and the execution time.

    Decitions:

    Because evaluating expressions strings like "1+2+3*4/3" is kind of tricky in pure java, i decided to use the PythonInterpreter class of Jython to solve the input expresssion.

    This example follows an "code first" approach. The WSDL file and XSD file is generated by the JAX-WS framework. After starting the JETTY servlet container ( step 10. ), the WSDL/XSD locations are:
    WSDL: http://localhost:9999/calc?wsdl
    XSD: http://localhost:9999/calc?xsd=1

    Download the complete project: CalcWS.tar.gz

    Index:

    1. create project structure with maven2
    2. customize pom.xml
    3. webservice bean src/main/java/at/st0ne/CalcWS.java.html
    4. calculator interface src/main/java/at/st0ne/Calc.java.html
    5. result message definition src/main/java/at/st0ne/messages/CalcResult.java
    6. the calculator implementation src/main/java/at/st0ne/CalcImpl.java
    7. src/main/webapp/WEB-INF/web.xml
    8. wire things together src/main/webapp/WEB-INF/applicationContext.xml
    9. compile and package war file
    10. start application in jetty
    11. a python/suds test client python/client.py

    input message sample:

    <?xml version="1.0" encoding="UTF-8"?>
    <SOAP-ENV:Envelope xmlns:ns0="http://st0ne.at/" 
                       xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/"
                       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                       xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
       <SOAP-ENV:Header/>
       <ns1:Body>
          <ns0:calculate>
             <inputString>9*3+14*3+1+7+6+1*2^2*(1+9999999)/0xf</inputString>
          </ns0:calculate>
       </ns1:Body>
    </SOAP-ENV:Envelope>
    

    result message sample:

    <?xml version='1.0' encoding='UTF-8'?>
    <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
       <S:Body>
          <ns2:calculateResponse xmlns:ns2="http://st0ne.at/">
             <return>
                <execTime>2</execTime>
                <result>1333248</result>
             </return>
          </ns2:calculateResponse>
       </S:Body>
    </S:Envelope>
    
    

    1. create project structure:

    mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp \
                           -DgroupId=at.st0ne \
                           -DartifactId=CalcWS \
                           -DinteractiveMode=false
    

    2. customize pom.xml:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>at.st0ne</groupId>
      <artifactId>CalcWS</artifactId>
      <packaging>war</packaging>
      <version>1.0-SNAPSHOT</version>
      <name>CalcWS Maven Webapp</name>
      <url>http://maven.apache.org</url>
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
        </dependency>
    
       <!-- JAX-WS -->
       <dependency>
         <groupId>com.sun.xml.ws</groupId>
         <artifactId>jaxws-rt</artifactId>
         <version>2.2.7</version>
       </dependency>
    
       <!-- Spring framework -->
       <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring</artifactId>
         <version>2.5.6</version>
       </dependency>
    
       <!-- Library from java.net, integrate Spring with JAX-WS -->
       <dependency>
          <groupId>org.jvnet.jax-ws-commons.spring</groupId>
          <artifactId>jaxws-spring</artifactId>
          <version>1.8</version>
          <exclusions>
             <exclusion>
                   <groupId>org.springframework</groupId>
                   <artifactId>spring-core</artifactId>
             </exclusion>
             <exclusion>
                   <groupId>org.springframework</groupId>
                   <artifactId>spring-context</artifactId>
             </exclusion>
             <exclusion>
                   <groupId>com.sun.xml.stream.buffer</groupId>
                   <artifactId>streambuffer</artifactId>
             </exclusion>
             <exclusion>
                   <groupId>org.jvnet.staxex</groupId>
                   <artifactId>stax-ex</artifactId>
             </exclusion>
          </exclusions>
       </dependency>
    
        <!-- jython for embeding python code -->
        <dependency>
          <groupId>jython</groupId>
          <artifactId>jython</artifactId>
          <version>2.1</version>
        </dependency>
      </dependencies>
      <build>
        <finalName>CalcWS</finalName>
        <plugins>
          <!-- JETTY plugin for fast testing -->
          <plugin>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>maven-jetty-plugin</artifactId>
            <version>6.1.5</version>
            <configuration>
              <scanIntervalSeconds>2</scanIntervalSeconds>
              <contextPath>/</contextPath>
              <connectors>
                <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
                  <port>9999</port>
                  <maxIdleTime>60000</maxIdleTime>
                </connector>
              </connectors>
            </configuration>
          </plugin>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.3.1</version>
            <configuration>
              <source>1.6</source>
              <target>1.6</target>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </project>
    

    3. src/main/java/at/st0ne/CalcWS.java.html:

    package at.st0ne;
    
    import javax.jws.WebMethod;
    import javax.jws.WebService;
    import javax.jws.WebParam;
    
    import at.st0ne.messages.CalcResult;
    
    @WebService
    public class CalcWS {
       // Spring Dependency Injection
       // Calc interface
       Calc calc;
       
       // Spring setter
       @WebMethod(exclude=true)
       public void setCalc(Calc calc) {
          this.calc = calc;
       }
       
       @WebMethod(operationName="calculate")
       public CalcResult calculate( @WebParam(name = "inputString") String inputString ) {
          return calc.calculate( inputString );
    
       }
    
    }
    

    4. src/main/java/at/st0ne/Calc.java.html:

    package at.st0ne;
    import at.st0ne.messages.CalcResult;
    
    public interface Calc {
       CalcResult calculate(String inputString);
    }
    

    5. src/main/java/at/st0ne/messages/CalcResult.java:

    package at.st0ne.messages;
    
    import javax.xml.bind.annotation.XmlAttribute;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlRootElement;
    
    @XmlRootElement
    public class CalcResult {
    
       private long execTime;
       private String result;
    
       @XmlElement
       public long getExecTime() {
          return this.execTime;
       }
    
       public void setExecTime(long execTime) {
          this.execTime = execTime;
       }
    
       @XmlElement
       public String getResult() {
          return this.result;
       }
    
       public void setResult(String result) {
          this.result = result;
       }
    }
    

    6. src/main/java/at/st0ne/CalcImpl.java:

    package at.st0ne;
    
    import at.st0ne.Calc;
    import at.st0ne.messages.CalcResult;
    
    import org.python.util.PythonInterpreter;
    
    public class CalcImpl implements Calc {
       private static PythonInterpreter py;
    
       CalcImpl() {
          this.py = new PythonInterpreter();
       }
    
       public CalcResult calculate(String inputString) {
    
          long start = System.currentTimeMillis();
          CalcResult r = new CalcResult();
          r.setResult(py.eval( inputString).toString());
          r.setExecTime( System.currentTimeMillis() - start );
          return r;
       }
    
    }
    

    7. src/main/webapp/WEB-INF/web.xml:

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    
    <web-app id="CalcWS"
      xmlns="http://java.sun.com/xml/ns/j2ee" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
      http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    
      <display-name>CalcWS</display-name>
    
      <servlet>
        <servlet-name>jaxws-servlet</servlet-name>
        <servlet-class>
          com.sun.xml.ws.transport.http.servlet.WSSpringServlet
        </servlet-class>
      </servlet>
    
      <servlet-mapping>
        <servlet-name>jaxws-servlet</servlet-name>
        <url-pattern>/calc</url-pattern>
      </servlet-mapping>
    
       <listener>
          <listener-class>
             org.springframework.web.context.ContextLoaderListener
          </listener-class>
       </listener>
    
    </web-app>
    

    8. wire things together src/main/webapp/WEB-INF/applicationContext.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:wss="http://jax-ws.dev.java.net/spring/servlet"
           xmlns:ws="http://jax-ws.dev.java.net/spring/core"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                               http://jax-ws.dev.java.net/spring/core http://jax-ws.dev.java.net/spring/core.xsd
                               http://jax-ws.dev.java.net/spring/servlet http://jax-ws.dev.java.net/spring/servlet.xsd"
    >
    
        <wss:binding url="/calc">
          <wss:service>
            <ws:service bean="#calcWS"/>
          </wss:service>
        </wss:binding>
    
        <!-- Web service methods -->
        <bean id="calcWS" class="at.st0ne.CalcWS">
          <property name="calc" ref="CalculatorImplementation" />
        </bean>
    
        <bean id="CalculatorImplementation" class="at.st0ne.CalcImpl" />
    
    </beans>
    
    

    9. compile and package war file

    mvn clean
    mvn compile
    mvn package
    

    10. start application in jetty:

    mvn run:jetty
    

    11. python/suds test client python/client.py:

    #!/usr/bin/python
    
    import suds
    import logging
    from suds import *
    from suds.client import Client
    
    handler = logging.StreamHandler(sys.stderr)
    logger = logging.getLogger('suds.transport.http')
    logger = logging.getLogger('suds.client')
    logger.setLevel(logging.DEBUG), handler.setLevel(logging.DEBUG)
    logger.addHandler(handler)
    
    
    client = Client('http://localhost:9999/calc?wsdl', timeout=30)
    
    
    print client
    
    print client.service.calculate('9*3+14*3+1+7+6+1*2^2*(1+9999999)/0xf')
    
    

    Dec 05 2012 10:22
    by st0ne
    ? hits
    • comment @Twitter
    • share on Twitter
©2012 Robert Steininger aka st0ne
CC-BY-SA